﻿#ifndef YINSHU_H
#define YINSHU_H

#include <string>
#include <string.h>

#if defined(WIN32)
#ifdef YINSHU_INTERFACE_EXPORTS
#define YINSHU_INTERFACE_API __declspec(dllexport)
#else
#define YINSHU_INTERFACE_API __declspec(dllimport)
#endif
#else
#if defined(YINSHU_INTERFACE_EXPORTS)
#define YINSHU_INTERFACE_API __attribute__((visibility("default")))
#else
#define YINSHU_INTERFACE_API
#endif
#endif

#define YINSHU_VERSION "3.1.0"

#ifdef __cplusplus
extern "C" {
#endif
/**
 * 错误码
 * @VVSuccess						加入房间成功
 * @VVConnectFail					连接服务器失败
 * @VVCreateMediaSessionFail			创建媒体会话失败
 * @VVAlreadyJoined					重复加入
 */
enum ErrorCode {
  VVSuccess = 0,
  VVConnectFail,
  VVCreateMediaSessionFail,
  VVAlreadyJoined
};

/**
 * 媒体会话类型
 * @Audio					语音通话
 * @Video					视频通话
 */
enum MediaType { Audio = 0, Video, AudioVideo, None };
//带宽自适应策略
enum NetAdaptPolicy{
  NAP_NO_ADAPTING=0,
  NAP_RESOLUTION_FIXED=1,//分辨率不调整，只调整码率和帧率,帧率5以下不再可调整，会卡顿，因此不同分辨率码率标准不一样
  NAP_RESOLUTION_DYNAMIC=2 //分辨率可调整，可动态适应较大带宽范围，100K-2M以内皆可以
};

typedef void (*void_ptr)(void* userData);
typedef void (*void_ptr_bool)(void* userData, bool param1);
typedef void (*void_ptr_str)(void* userData, const char* param1);
typedef void (*void_ptr_str_str)(void* userData,
                                 const char* param1,
                                 const char* param2);
typedef void (*void_ptr_int_bool)(void* userData, MediaType type, bool param1);
typedef void (*void_ptr_str_bool)(void* userData,
                                  const char* param1,
                                  bool param2);
//用户音量回调成员ID，音量值
typedef void (*void_ptr_str_int)(void* userData,
                                   const char* param1,
                                   int volume);
//媒体带宽信息回调,上行带宽，下行带宽
typedef void (*void_ptr_float_float)(void* userData,
                                     float up_bandwidth,
                                     float down_bandwidth);
//媒体接收状态回调成员ID,媒体链路信息json格式，
//json格式如下:
/*
{
    {"peerName",_peerName},            // 对端名称
    {"isVideo",_is_video},             // 是否是视频
    {"codecName",_codecName},           // 媒体编码名称
    {"width",_width},                  // 视频分辨率宽
    {"height",_height},                // 视频分辨率高
    {"level_or_fps",_level_or_fps},     // 音频输入级别或者视频帧率
    {"packets",_packets},              // 包数
    {"packetLoss",_packetLoss},        // 丢包数
    {"bytes",_bytes},                  // 字节数
    {"lossRate",_lossRate},            // 丢包率
    {"bitRate",_bitrate},              // 媒体码率
    {"delayMs",_delayMs}              // 当前延迟（毫秒）
  };
*/
typedef void (*void_ptr_str_str)(void* userData,const char* peerName,const char* linkJson);


// 信令回调集合
struct SignalCallbacks_ {
  // 权限变化回调 param1：成员ID  param2：true 授权，false 取消授权
  void_ptr_str_bool OnRecvContrlAuth = nullptr;
  // 角色变化回调 role(param1): "student"/"visitor"; memberId(param2)成员ID
  void_ptr_str_str OnRecvRoleChanged = nullptr;
  // 会议开始回调 param1 json字符串
  void_ptr_str OnRoomStarted = nullptr;
  // 会议结束回调
  void_ptr OnRoomStoped = nullptr;
  // 远端改变本地音、视频状态的回调  type：媒体类型  param1：true 开启 false
  // 关闭
  void_ptr_int_bool OnModifyMediaStatus = nullptr;
  // 全体禁音禁视回调 type：媒体类型 param1：true 关闭全体禁止 false
  // 开启全体禁止
  void_ptr_int_bool OnRoomMediaStatus = nullptr;
  // 收到控制权限申请 param1：成员ID  param2：true 申请，false 取消申请
  void_ptr_str_bool OnRequestControlAuth = nullptr;
  // 收到变换角色申请 param1：成员ID  param2：true 申请，false 取消申请
  void_ptr_str_bool OnRequestChangeRole = nullptr;
  // 当前房间成员列表 param1:当前房间内成员列表信息 json格式字符串
  void_ptr_str OnRoomPeers = nullptr;
  // 成员加入房间 param1:成员信息 json格式字符串
  void_ptr_str OnPeerJoined = nullptr;
  // 成员离开房间 param1:成员ID 字符串类型
  void_ptr_str OnPeerLeaved = nullptr;
  // 成员被踢出房间 param1:成员ID
  void_ptr_str OnPleaseGoout = nullptr;
  // 收到系统信令 param1: 信令名称  param2: 信令数据，json格式字符串
  void_ptr_str_str OnRecvSysSignal = nullptr;
  //媒体接收状态回调 param1：成员ID,,媒体链路信息json格式,是一个数组，
  void_ptr_str_str OnMediaLinkInfo= nullptr;
  //总体媒体状态回调,总上行带宽，总体下行带宽
  void_ptr_float_float OnMediaBandWidthInfo = nullptr;
  // 音量回调
  void_ptr_str_int OnPeerAudioVolumne = nullptr;
  //屏幕共享回调,
  /*数据格式:
  {
    ok: false,   // true可以，false不可以。
    reason: 'another user is screen sharing'
  }.
  */
  void_ptr_str OnEnableScreenshare =nullptr;
};
typedef struct SignalCallbacks_ SignalCallbacks;
//用户信息
struct DeviceInfo{
  int nDeviceIndex{0};
  char pDeviceName[256]{0};
  //ID
  char pDeviceId[256]{0};
  //true为麦克，false为扬声器
  bool in{true};
   
  //默认构造函数
  DeviceInfo() = default;
  //构造函数
  DeviceInfo(int index, const char* name, const char* id, bool isIn=true)
      : nDeviceIndex(index),in(isIn) {
    strcpy(pDeviceName, name); 
    strcpy(pDeviceId,id);
  }
  //=赋值运算符重载
  DeviceInfo& operator=(const DeviceInfo& other) {
    nDeviceIndex = other.nDeviceIndex;
    strcpy(pDeviceName,other.pDeviceName); 
    strcpy(pDeviceId,other.pDeviceId);
    in = other.in;
    return *this;
  }
  //比较两个项目相同
  bool operator==(const DeviceInfo& other) const {
    return (strcmp(pDeviceId,other.pDeviceId)==0);
  }
} ;
/**
 * 创建yinshu句柄
 * 业务逻辑 跟随主程序一起创建
 * @return yinshu句柄
 */
YINSHU_INTERFACE_API void* CreateYinshuInstance();

/**
 * 销毁Yinshu句柄
 * 业务逻辑 在主程序要退出时调用,并内部调用ClearYinshu清楚内部资源
 * @param handle				Yinshu句柄
 */
YINSHU_INTERFACE_API void DestoryYinshuInstance();
/**
 * 打开trace日志
 * @param handle yinshu句柄
 * @param enable							日志看开关，enable=true
 * 打开日志，false关闭
 * @param level	 0-debug,1-warning,2-error
 */
YINSHU_INTERFACE_API void SetLoggerLevel(void* handle,
                                             bool enable,
                                             int level);

/**
 * 初始化yinshuSDK.
 * 业务逻辑 在创建房间时调用
 * @param handle yinshu句柄
 * @param userData						用户自定义数据
 * @param OnJoined
 * 加入房间回调,调用JoinRoom后会触发
 * @param OnDisConnected，1099错误码表示被踢出去了
 * 断开连接回调,当此回调被触发时，要依次调用LeaveRoom()， ReleaseSdk()来释放资源
 * @param OnNewMemberJoined
 * 新成员加入房间回调，在此回调中调用SetRenderWindow()接口来设置新成员视频渲染窗口句柄
 * @param OnMemberLeft
 * 成员离开房间回调，其它成员调用LeaveRoom后会触发
 * @param OnMemberEnableVideo			成员打开视频回调
 * @param OnMemberDisableVideo			成员关闭视频回调
 * @param OnMemberUnMuteAudio			成员打开音频回调
 * @param OnMemberMuteAudio				成员关闭音频回调
 * @param OnSessionError
 * 会话失败回调，会话失败的原因包括设备被占用，网络堵塞导致消息超时，消息内容错误等等
 * @param OnDevicesChange
 * 设备变化检测，比如摄像头，麦克风，扬声器等
 */
YINSHU_INTERFACE_API void InitSDK(
    void* handle,
    void* userData,
    void (*OnJoined)(void* userData, ErrorCode eCode),
    void (*OnDisConnected)(void* userData, int errCode),
    void (*OnNewMemberJoined)(void* userData,
                              const char* pMemberId,
                              const char* pDisplayName,
                              int cameras,
                              int mics),
    void (*OnMemberLeft)(void* userData,
                         const char* pMemberId,
                         const char* pDisplayName),
    void (*OnMemberEnableVideo)(void* userData,
                                const char* pMemberId,
                                const char* pDisplayName),
    void (*OnMemberDisableVideo)(void* userData,
                                 const char* pMemberId,
                                 const char* pDisplayName),
    void (*OnMemberEnableScreenShare)(void* userData,
                                      const char* pMemberId,
                                      const char* pDisplayName),
    void (*OnMemberDisableScreenShare)(void* userData,
                                       const char* pMemberId,
                                       const char* pDisplayName),
    void (*OnMemberUnMuteAudio)(void* userData,
                                const char* pMemberId,
                                const char* pDisplayName),
    void (*OnMemberMuteAudio)(void* userData,
                              const char* pMemberId,
                              const char* pDisplayName),
    void (*OnRecvUserMessage)(void* userData, const char* pUserMessage),
    void (*OnSessionError)(void* userData, const char* reason),
    void (*OnDevicesChanged)(void* userData,
                             const char* pPeerId,
                             int cameras,
                             int mics,
                             int speakers,
                             int suggestMic,//新插入后新增或者拔后默认麦克风索引
                             int suggestSpeaker//新插入后新增或者拔后默认扬声器索引
                             ),
    SignalCallbacks* callbacks = nullptr);

/**
 * 销毁yinshuSDK内部资源.
 * 业务逻辑 在销毁房间时调用
 * @param handle					yinshu句柄
 */
YINSHU_INTERFACE_API void ReleaseSdk(void* handle);

/**
 * 指定视频渲染窗口.
 * 业务逻辑
 * 针对本地视频，在JoinRoom()之前调用，针对远端视频在收到OnMemberEnableVideo()回调时调用
 * @param handle					yinshu句柄
 * @param pMemberId				成员标识符
 * @param pRemoteRenderWin       渲染窗口句柄
 * @param bMirror
 * 是否镜像，一般本地图像为true，远端为false
 */
YINSHU_INTERFACE_API void SetRenderWindow(void* handle,
                                           const char* pMemberId,
                                           void* pRenderWin,
                                           bool bMirror);

/**
 * 指定屏幕共享渲染窗口.
 * 业务逻辑
 * 针对本地视频，在JoinRoom()之前调用，针对远端视频在收到OnMemberEnableScreenShare()回调时调用
 * @param handle					yinshu句柄
 * @param pMemberId				成员标识符
 * @param pRemoteRenderWin       渲染窗口句柄
 * @param bMirror
 * 是否镜像，一般本地图像为true，远端为false
 */
YINSHU_INTERFACE_API void SetScreenShareRenderWindow(void* handle,
                                                      const char* pMemberId,
                                                      void* pRenderWin,
                                                      bool bMirror);

/**
 * 加入房间.
 * 业务逻辑 在创建房间后，主动开启视频会议时调用
 * @param handle					yinshu句柄
 * @param dispatchServer 调度服务器
 * @param pRoomId						房间号
 * @param passwd							房间密码
 * @param eMediaType						媒体会话类型
 * @param pMemberId
 * 成员标识符，必须在当前房间中保持唯一
 * @param pDisplayName					成员昵称
 * @param avatarUrl						成员头像链接
 * @param role							成员校色
 * @return const char*
 * 返回值为json字符串，NULL表示失败，否则返回形式如{"code":0,"message":"sucessful"};
 */
YINSHU_INTERFACE_API const char* JoinRoom(void* handle,
                                           const char* dispatchServer,
                                           const char* pRoomId,
                                           const char* passwd,
                                           MediaType eMediaType,
                                           const char* pMemberId,
                                           const char* pDisplayName,
                                           const char* avatarUrl,  // 头像地址
                                           bool simulcastVideo=false);

/**
 * 离开房间.
 * 业务逻辑 在创建房间后，主动关闭视频会议时调用
 * @param handle					yinshu句柄
 */
YINSHU_INTERFACE_API void LeaveRoom(void* handle);
/*******************************************
 * 以下为流媒体相关接口
 */

/**
 * 打开指定成员视频(包括自己)
 * 业务逻辑
 * 默认状态下是接受所有房间成员视频，如果调用过DisableMemberVideo()后，可以通过此接口接收指定成员视频
 * @param handle						yinshu句柄
 * @param pMemberId					成员标识符
 * @param EnableMemberVideoResult	接收指定成员视频回调
 */
YINSHU_INTERFACE_API void EnableMemberVideo(
    void* handle,
    const char* pMemberId,
    void (*EnableMemberVideoResult)(void* userData,
                                    bool bSucc,
                                    const char* pMemberId));

/**
 * 关闭指定成员视频(包括自己)
 * 业务逻辑 默认状态下是接受所有房间成员视频，通过此接口可以不接收指定成员视频
 * @param handle						yinshu句柄
 * @param pMemberId					成员标识符
 * @param DisableMemberVideoResult	不接收指定成员视频回调
 */
YINSHU_INTERFACE_API void DisableMemberVideo(
    void* handle,
    const char* pMemberId,
    void (*DisableMemberVideoResult)(void* userData,
                                     bool bSucc,
                                     const char* pMemberId));

/**
 * 只收看指定成员视频,其他成员视频不接收,但不处理本地视频
 * @param handle						yinshu句柄
 * @param membersJosonString	成员id json数组字符串
*/
YINSHU_INTERFACE_API void RecvMembersVideo(
  void* handle,
  const char* membersJosonString);

/**
 * 在支持simulcast情况下，设定收取指定非本地成员视频的分辨率类型,
 * @param pMemberId	成员id,字符串类型
 * @param type ，字符串类型 low为小视频,medium为中视频，high为大视频
 * @return void
*/
YINSHU_INTERFACE_API void SetMemberVideoProfile(
  void* handle,  
  const char* pMemberId,
  const char* profile);
/**
 * 打开指定成员音频(包括自己)
 * 业务逻辑
 * 默认状态下是接受所有房间成员音频，如果调用过DisableMemberAudio()后，可以通过此接口接收指定成员音频
 * @param handle						yinshu句柄
 * @param pMemberId					成员标识符
 * @param EnableMemberVideoResult	接收指定成员音频回调
 */
YINSHU_INTERFACE_API void EnableMemberAudio(
    void* handle,
    const char* pMemberId,
    void (*EnableMemberAudioResult)(void* userData,
                                    bool bSucc,
                                    const char* pMemberId));

/**
 * 关闭指定成员音频(包括自己)
 * 业务逻辑 默认状态下是接受所有房间成员音频，通过此接口可以不接收指定成员音频
 * @param handle						yinshu句柄
 * @param pMemberId					成员标识符
 * @param DisableMemberAudioResult	不接收指定成员视频回调
 */
YINSHU_INTERFACE_API void DisableMemberAudio(
    void* handle,
    const char* pMemberId,
    void (*DisableMemberAudioResult)(void* userData,
                                     bool bSucc,
                                     const char* pMemberId));

/**
 * 获取视频设备信息.
 * @param handle						yinshu句柄
 * @param GetVideoDevicesResult	获取视频设备信息回调
 */
YINSHU_INTERFACE_API void GetVideoDevices(
    void* handle,
    void (*GetVideoDevicesResult)(void* userData,
                                  const DeviceInfo sDeviceInfos[],
                                  int nDeviceNum));

/**
 * 获取音频设备信息.
 * @param handle						yinshu句柄
 * @param in                      true 获取输入设备，false 获取输出设备
 * @param GetAudioDevicesResult	获取音频设备信息回调
 */
YINSHU_INTERFACE_API void GetAudioDevices(
    void* handle,
    bool in,
    void (*GetAudioDevicesResult)(void* userData,
                                  const DeviceInfo sDeviceInfos[],
                                  int nDeviceNum,
                                  bool in));
/**
 * 设置音频设备，麦克风或者扬声器
 * @param handle yinshu句柄
 * @param in  true为输入设备麦克风，false 为播放设备扬声器
 * @param index  设备索引
 */
YINSHU_INTERFACE_API void SetAudioDevice(void* handle, bool in, int index);
/**
 * 指定摄像头.
 * @param handle						yinshu句柄
 * @param nIndex						摄像头序列号
 */
YINSHU_INTERFACE_API void SetVideoDevice(void* handle, int nIndex);

/**
 * 获取指定摄像头支持的分辨率列表，以及帧率列表
 * @param handle  yinshu句柄
 * @param nIndex  摄像头索引
 * @return 返回json数据格式，包含分辨率列表以及帧率列表
 */
YINSHU_INTERFACE_API const char* GetVideoDeviceJson(void* handle, int nIndex);
/**
 * 指定输入分辨率.
 * @param handle						yinshu句柄
 * @param pWidth						宽度
 * @param pHeight					高度
 */
YINSHU_INTERFACE_API void SetVideoSize(
    void* handle,
    int nWidth,
    int nHeight);

/*******************************************
 * 以下为屏幕共享接口
 */

/**
 * 开始屏幕共享.
 * @param handle						yinshu句柄
 * @param fps		共享屏幕帧率,共享屏幕帧率尽量在15帧以下
 */
YINSHU_INTERFACE_API void EnableScreenShare(void* handle, int fps = 10);

/**
 * 停止屏幕共享.
 * @param handle						yinshu句柄
 */
YINSHU_INTERFACE_API void DisableScreenShare(void* handle);

/*******************************************
 * 其他接口
 */

/**
 * 发送用户自定义数据.
 * @param handle						yinshu句柄
 * @param peers
 *json格式成员列表,为json字符串成员数组，NULL或者空数组[]表示
 *									发送给房间所有成员，否则
 *"[\"aa\",\"bb\",\"cc\"]" 发给指定成员
 * @param data						自定义json格式数据内容
 */
YINSHU_INTERFACE_API void SendUserMessage(void* handle,
                                           const char* peers,
                                           const char* data);

/**
 * 发送用户自定义数据.
 * @param handle						yinshu句柄
 * @param OnGetUserMessageHistory	消息内容回调，data为json格式
 */
YINSHU_INTERFACE_API void GetUserMessageHistory(
    void* handle,
    void (*OnGetUserMessageHistory)(void* userData, const char* data));

// 申请控制权限 TRUE 申请权限 FALSE 取消权限申请
YINSHU_INTERFACE_API void RequestControlAuth(void* handle, bool req);
// 申请音视频权限 TRUE 申请音视频权限
YINSHU_INTERFACE_API void RequestChangeRole(void* handle, bool req);
// 将成员移出会议
YINSHU_INTERFACE_API void RemoveMember(void* handle,
                                        const char* memberId,
                                        const char* displayName);

// 会议开始/结束
YINSHU_INTERFACE_API void RoomStart(void* handle);
YINSHU_INTERFACE_API void RoomStop(void* handle);
//

/**
 * 控制远端成员的音、视频状态
 * @param handle		yinshu句柄
 * @param memberId	成员ID
 * @param type       媒体类型
 * @param state      开关状态
 */
YINSHU_INTERFACE_API void ModifyMemberMediaStatus(void* handle,
                                                   const char* memberId,
                                                   MediaType type,
                                                   bool state);

// 全体禁音禁视 不包括主持人 state: false 全体禁止、true：解除全体禁止

/**
 * 全体禁音禁视 不包括主持人
 * @param handle		yinshu句柄
 * @param type       媒体类型
 * @param state      开关状态 false 开启、true 关闭
 */
YINSHU_INTERFACE_API void ModifyRoomMediaStatus(void* handle,
                                                 MediaType type,
                                                 bool state);

/**
 * 授予/取消 权限
 * @param handle		yinshu句柄
 * @param memberId	成员ID
 * @param bAuth      true 授予权限、false 取消权限
 */
YINSHU_INTERFACE_API void ModifyMemberAuth(void* handle,
                                            const char* memberId,
                                            bool bAuth);

/**
 * 修改成员角色
 * @param handle		yinshu句柄
 * @param memberId	成员ID
 * @param role       目标角色 "student"/"visitor"
 */
YINSHU_INTERFACE_API void ModifyMemberRole(void* handle,
                                            const char* memberId,
                                            const char* role);

/*
 * 发送系统信令
 * @param handle		yinshu句柄
 * @param sigName	信令名称
 * @param jsonStr	信令参数 json格式字符串
 * @param successCallBack	成功回调
 * @param failCallBack		失败回调
 */
YINSHU_INTERFACE_API void SendSysSignal(
    void* handle,
    const char* sigName,
    const char* jsonStr,
    void (*successCallBack)(const char* data, void* userdata) = nullptr,
    void (*failCallBack)(const char* data, void* userdata) = nullptr);

/*
 * 更新昵称 （备注：修改名称成功后，需要更新SDK缓存的昵称）
 * @param handle			yinshu句柄
 * @param displayName	昵称
 */
YINSHU_INTERFACE_API void UpdateDisplayName(void* handle,
                                             const char* displayName);

/**
 * 获取当前音频设备索引，麦克风或者扬声器
 * @param handle			yinshu句柄
 * @param in  true为输入设备麦克风，false 为播放设备扬声器
 * @return 麦克风或者扬声器  设备索引
 *
 */
YINSHU_INTERFACE_API int GetCurrentAudioDevice(void* handle, bool in);
/**
 * 获取当前摄像头索引
 * @param handle			yinshu句柄
 * @return 摄像头  设备索引
 *
 */
YINSHU_INTERFACE_API int GetCurrentCamera(void* handle);
/**
 * @description: 开始录制接口
 * @param {void*} handle,vvsdk句柄
 * @param {char*} path_fileName，录制文件名
 * @return {*}
 */
YINSHU_INTERFACE_API void   StartRecord(void* handle, const char* path_fileName);
/**
 * @description: 停止录制
 * @param {void*} handle，操作句柄
 * @return {*}
 */
YINSHU_INTERFACE_API void   StopRecord(void* handle);

/**
 * @description: 设置网络敏感度，用于网络比较差的情况
 * @param {char*} level，"weak"--弱敏感，"middle"--比较敏感,"strong"---非常敏感
 * @return {*}
 */
YINSHU_INTERFACE_API void SetNetworkSensitivity(const char* level);
/**
 * @description: 设置网络敏感度，用于网络比较差的情况
 * @param {void*} handle,音书句柄
 * @param {bool} enable，true--开启，false--关闭
 * @param {int} interval，检测间隔，单位毫秒，默认3000毫秒
 * @return {*}
 */
YINSHU_INTERFACE_API void EnableLinkCheck(void* handle, bool enable=true,int interval=3000);
/**
* @description: 设置码率
* @param {void*} handle, yinshu句柄
* @param {int} bitrate, 码率
* @return {*}
*/
YINSHU_INTERFACE_API void SetBitrate(void* handle, int bitrate);
/**
* @description: 设置帧率
* @param {void*} handle, yinshu句柄
* @param {int} framerate, 帧率
* @return {*}
*/
YINSHU_INTERFACE_API void SetFramerate(void* handle, int framerate);
/**
* @description: 设置带宽策略
* @param {void*} handle, yinshu句柄
* @param {NetAdaptPolicy} policy, 带宽自适应策略
* @return {*}
*/
YINSHU_INTERFACE_API void SetNetAdaptPolicy(void* handle, NetAdaptPolicy policy);

YINSHU_INTERFACE_API void SetFramerate(void* handle, int framerate);
/**
* @description: 计算所需要带宽
* @param {int} width, 视频宽
* @param {int} height, 视频高
* @param {bool} simulcast, 是否支持大小流
* @return {int} 返回所需带宽
*/
YINSHU_INTERFACE_API int CaclBandWidthNeeded(int width,int height,bool simulcast);
#ifdef __cplusplus
}
#endif
#endif